﻿using System;
using UniRx;
using UniRx.Operators;

/// <summary>
/// D触发器
/// </summary>
internal class DifferentTriggerObservable<TSource, TControlOn, TControlOff> : OperatorObservableBase<TSource>
{
    private readonly IObservable<TSource> m_Source;
    private readonly IObservable<TControlOn> m_ControlOn;
    private readonly IObservable<TControlOff> m_ControlOff;

    public DifferentTriggerObservable(IObservable<TSource> source, IObservable<TControlOn> controlOn, IObservable<TControlOff> controlOff)
        : base(source.IsRequiredSubscribeOnCurrentThread())
    {
        m_Source = source;
        m_ControlOn = controlOn;
        m_ControlOff = controlOff;
    }

    protected override IDisposable SubscribeCore(IObserver<TSource> observer, IDisposable cancel)
    {
        return new SourceObserver(this, observer, cancel).Run();
    }

    // 输入流观察者
    internal class SourceObserver : OperatorObserverBase<TSource, TSource>
    {
        private readonly DifferentTriggerObservable<TSource, TControlOn, TControlOff> m_Parent;
        private object m_Gate = new object();
        private bool m_IsToggleOn = true;

        public SourceObserver(DifferentTriggerObservable<TSource, TControlOn, TControlOff> parent, IObserver<TSource> observer, IDisposable cancel) : base(observer, cancel)
        {
            m_Parent = parent;
        }

        public IDisposable Run()
        {
            var sourceSubscription = m_Parent.m_Source.Subscribe(this);
            var controlOnSubscription = m_Parent.m_ControlOn.Subscribe(new RisingEdgeObserver(this));
            var controlOffSubscription = m_Parent.m_ControlOff.Subscribe(new FallingEdgeObserver(this));

            return StableCompositeDisposable.Create(sourceSubscription, controlOnSubscription, controlOffSubscription);
        }

        // 输入流信号传递
        public override void OnNext(TSource value)
        {
            lock (m_Gate)
            {
                if (m_IsToggleOn)
                {
                    observer.OnNext(value);
                }
            }
        }

        public override void OnError(Exception error)
        {
            lock (m_Gate)
            {
                try { observer.OnError(error); } finally { Dispose(); }
            }
        }

        public override void OnCompleted()
        {
            lock (m_Gate)
            {
                try { observer.OnCompleted(); } finally { Dispose(); }
            }
        }

        internal class RisingEdgeObserver : IObserver<TControlOn>
        {
            private readonly SourceObserver parent;

            public RisingEdgeObserver(SourceObserver parent)
            {
                this.parent = parent;
            }

            // 上升沿信号处理
            public void OnNext(TControlOn value)
            {
                lock (parent.m_Gate)
                {
                    parent.m_IsToggleOn = true;
                }
            }

            public void OnError(Exception error)
            {
            }

            public void OnCompleted()
            {
            }
        }

        internal class FallingEdgeObserver : IObserver<TControlOff>
        {
            private readonly SourceObserver parent;

            public FallingEdgeObserver(SourceObserver parent)
            {
                this.parent = parent;
            }

            // 下降沿信号处理
            public void OnNext(TControlOff value)
            {
                lock (parent.m_Gate)
                {
                    parent.m_IsToggleOn = false;
                }
            }

            public void OnError(Exception error)
            {
            }

            public void OnCompleted()
            {
            }
        }
    }
}